home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / os2 / tktools.zip / typefast / typefast.c < prev    next >
Text File  |  1992-07-17  |  20KB  |  566 lines

  1. /* TYPEFAST for PM is written by Turgut Kalfaoglu <turgut@frors12.bitnet> */
  2. /* This code can be compiled with IBM C/SET 2 Compiler                    */
  3.  
  4.  
  5. #define INCL_WIN
  6. #define INCL_GPI
  7. #define INCL_DOSDATETIME
  8. #include <os2.h>                        /* PM header file               */
  9.  
  10. #include "typefast.h"                   /* Resource symbolic identifiers*/
  11. #include <io.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <ctype.h>
  15.  
  16. MRESULT EXPENTRY MyWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  17. CHAR *findword(void);
  18.                                         /* Define parameters by type    */
  19. HAB  hab;                               /* PM anchor block handle       */
  20. PSZ  pszErrMsg;
  21. POINTL pt;
  22. CHAR *words[30], kbbuf[256];
  23. INT wordx[30],wordy[30],activewords,lost,score,maxactivewords,timertime,difflevel;
  24. LONG CharHeight, CharWidth,   topx,topy;
  25. FILE *wordfile;
  26. BOOL anykeyhit,  pausemode,   gameover, sound,lastwordheight=0, respectCase=0;
  27. ULONG wordcount, wordcountcorr;
  28. float startsec;
  29. CHAR *copyright="TYPEFAST V1.1 (C)1992 Turgut Kalfaoglu <TURGUT@FRORS12.BITNET>";
  30.  
  31. INT main (VOID)
  32. {
  33.   HMQ  hmq;                             /* Message queue handle         */
  34.   HWND hwndClient = NULLHANDLE;         /* Client area window handle    */
  35.   HWND hwndFrame  = NULLHANDLE;         /* Frame window handle          */
  36.   QMSG qmsg;                            /* Message from message queue   */
  37.   ULONG flCreate;                       /* Window creation control flags*/
  38.  
  39.   init();
  40.  
  41.   if ((hab = WinInitialize(0)) == 0L) /* Initialize PM     */
  42.      AbortTypeFast(hwndFrame, hwndClient); /* Terminate the application */
  43.  
  44.   if ((hmq = WinCreateMsgQueue( hab, 0 )) == 0L)/* Create a msg queue   */
  45.      AbortTypeFast(hwndFrame, hwndClient); /* Terminate the application */
  46.  
  47.   if (!WinRegisterClass(                /* Register window class        */
  48.      hab,                               /* Anchor block handle          */
  49.      (PSZ)"MyWindow",                   /* Window class name            */
  50.      (PFNWP)MyWindowProc,               /* Address of window procedure  */
  51.      CS_SIZEREDRAW,                     /* Class style                  */
  52.      0                                  /* No extra window words        */
  53.      ))
  54.      AbortTypeFast(hwndFrame, hwndClient); /* Terminate the application */
  55.  
  56.    flCreate = FCF_STANDARD;             /* Set frame control flags to   */
  57.                                         /* standard                     */
  58.                                  
  59.  
  60.   if ((hwndFrame = WinCreateStdWindow(
  61.                HWND_DESKTOP,            /* Desktop window is parent     */
  62.                WS_VISIBLE,              /* STD. window styles           */
  63.                &flCreate,               /* Frame control flag           */
  64.                "MyWindow",              /* Client window class name     */
  65.                "TypeFast",              /* No window text               */
  66.                0L,                      /* No special class style       */
  67.                (HMODULE)0L,             /* Resource is in .EXE file     */
  68.                ID_WINDOW,               /* Frame window identifier      */
  69.                &hwndClient              /* Client window handle         */
  70.                )) == 0L)
  71.      AbortTypeFast(hwndFrame, hwndClient); /* Terminate the application */
  72.  
  73.   WinSetWindowText(hwndFrame, "TypeFast!");
  74.  
  75.   WinStartTimer(hab, hwndClient, 1, timertime);
  76.  
  77. /*
  78.  * Get and dispatch messages from the application message queue
  79.  * until WinGetMsg returns FALSE, indicating a WM_QUIT message.
  80.  */
  81.  
  82.   while( WinGetMsg( hab, &qmsg, 0L, 0, 0 ) )
  83.     WinDispatchMsg( hab, &qmsg );
  84.  
  85.   WinStopTimer(hab,hwndClient, 1);
  86.   WinDestroyWindow(hwndFrame);           /* Tidy up...                   */
  87.   WinDestroyMsgQueue( hmq );             /* Tidy up...                   */
  88.   WinTerminate( hab );                   /* Terminate the application    */
  89. } /* End of main */
  90.  
  91. /**************************************************************************
  92.  *
  93.  *  Name       : MyWindowProc
  94.  *
  95.  *  Description: The window procedure associated with the client area in
  96.  *               the standard frame window. It processes all messages
  97.  *               either sent or posted to the client area, depending on
  98.  *               the message command and parameters.
  99.  *
  100.  *  Parameters :  hwnd = window handle
  101.  *                msg = message code
  102.  *                mp1 = first message parameter
  103.  *                mp2 = second message parameter
  104.  *
  105.  *  Return     :  depends on message sent
  106.  *
  107.  *************************************************************************/
  108. MRESULT EXPENTRY MyWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  109. {
  110.   DATETIME dt;
  111.   static HWND hwndMenu;
  112.  
  113.   switch( msg )
  114.   {
  115.     case WM_CREATE:
  116.     {
  117.       INT i;
  118.       FONTMETRICS fm;
  119.       HPS hps;
  120.  
  121.       /* Learn size of characters */
  122.       hps = WinGetPS(hwnd);
  123.       GpiQueryFontMetrics(hps,(LONG) sizeof fm, &fm);
  124.       CharHeight = (INT) fm.lMaxBaselineExt;
  125.       CharWidth  = (INT) fm.lMaxCharInc;
  126.       if (CharHeight < 1 | CharHeight > 50)
  127.         notify(hwnd,"CharHeight is %d!",CharHeight);
  128.       if (CharWidth < 1 | CharWidth > 100)
  129.         notify(hwnd,"CharWidth is %d!",CharWidth);
  130.       WinReleasePS(hps);
  131.  
  132.       wordfile = fopen("TYPEFAST.DAT","rb");
  133.       if (wordfile == NULL) {
  134.          notify(hwnd,"Cannot find TYPEFAST.DAT");
  135.          WinPostMsg( hwnd, WM_QUIT, (MPARAM)0,(MPARAM)0 );
  136.       }
  137.  
  138.       kbbuf[0] = 0; /* init keyb buffer */
  139.       for (i=0;i<30;i++)
  140.          words[i] = (char *) malloc(sizeof(CHAR)*20);
  141.  
  142.       DosGetDateTime(&dt);
  143.       srand(dt.hours*100+dt.minutes*10+dt.seconds);
  144.       fseek (wordfile,(LONG) rand()%10240L, SEEK_CUR);
  145.  
  146.       hwndMenu = WinWindowFromID(WinQueryWindow(hwnd,QW_PARENT),FID_MENU);
  147.       difflevel = ID_EASY;
  148.       return 0;
  149.     }
  150.  
  151.     case WM_COMMAND:
  152.       {
  153.       USHORT command;                   /* WM_COMMAND command value     */
  154.       command = SHORT1FROMMP(mp1);      /* Extract the command value    */
  155.       switch (command)
  156.       {    
  157.       case ID_EASY:
  158.       case ID_MEDIUM:
  159.       case ID_HARD:
  160.  
  161.         /* remove check mark */
  162.           WinSendMsg(hwndMenu,MM_SETITEMATTR,
  163.                         MPFROM2SHORT(difflevel,TRUE),
  164.                         MPFROM2SHORT(MIA_CHECKED,0));
  165.           difflevel = COMMANDMSG(&msg)->cmd;
  166.           maxactivewords = 4;
  167.           timertime = difflevel;
  168.           WinStartTimer(hab, hwnd, 1, timertime);
  169.           WinSendMsg(hwndMenu,MM_SETITEMATTR,
  170.                         MPFROM2SHORT(difflevel,TRUE),
  171.                         MPFROM2SHORT(MIA_CHECKED,MIA_CHECKED));
  172.           return 0;
  173.  
  174.        case ID_ABOUT:
  175.           WinMessageBox(HWND_DESKTOP, 
  176.              hwnd,            /* Owner window is our frame */
  177.              "TypeFast allows you to practice your typing by providing you"
  178.              " with words of your choice (simply provide a text file to the"
  179.              " program by naming it TYPEFAST.DAT), and measures the time it"
  180.              " takes you to type words. You can use SPACE or RETURN between"
  181.              " words. The program stays in demo mode until you hit a key.\n"
  182.              "TypeFast for PM is written by Turgut Kalfaoglu, <turgut@frmop11.bitnet>\n"
  183.              "Shareware: $10 donation requested if you find it useful."
  184.              " Send donation to: Turgut Kalfaoglu, 1378 Sok 8/10, Izmir Turkey\n"
  185.              " Thank you for trying TYPEFAST!",
  186.              "About TypeFast",
  187.              MSGBOXID,           
  188.              MB_ICONEXCLAMATION | MB_OK ); /* Flags */
  189.           return 0;
  190.  
  191.        case ID_RESTART: 
  192.        {
  193.           INT keepdiff, keepsound;
  194.           keepdiff = difflevel;
  195.           keepsound = sound;
  196.           init();
  197.           difflevel = keepdiff;
  198.           sound  = keepsound;
  199.           timertime = difflevel;
  200.           WinStartTimer(hab,hwnd,1,timertime);
  201.           return 0;
  202.         }
  203.  
  204.         case ID_SOUND:
  205.           sound = !sound;
  206.           if (!sound) /* remove tick (check) mark */
  207.              WinSendMsg(hwndMenu,MM_SETITEMATTR,
  208.                         MPFROM2SHORT(ID_SOUND,TRUE),
  209.                         MPFROM2SHORT(MIA_CHECKED,FALSE));
  210.           else        /* put tick (check) mark    */
  211.              WinSendMsg(hwndMenu,MM_SETITEMATTR,
  212.                         MPFROM2SHORT(ID_SOUND,TRUE),
  213.                         MPFROM2SHORT(MIA_CHECKED,MIA_CHECKED));
  214.           return 0;
  215.  
  216.         case ID_CASE:
  217.           respectCase = !respectCase;
  218.           if (!respectCase)
  219.              WinSendMsg(hwndMenu,MM_SETITEMATTR,
  220.                         MPFROM2SHORT(ID_CASE,TRUE),
  221.                         MPFROM2SHORT(MIA_CHECKED,FALSE));
  222.           else
  223.              WinSendMsg(hwndMenu,MM_SETITEMATTR,
  224.                         MPFROM2SHORT(ID_CASE,TRUE),
  225.                         MPFROM2SHORT(MIA_CHECKED,MIA_CHECKED));
  226.           return 0;
  227.  
  228.         case ID_EXITPROG:
  229.           WinPostMsg( hwnd, WM_CLOSE, (MPARAM)0, (MPARAM)0 );
  230.           return 0;
  231.  
  232.         default:
  233.           return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  234.       }
  235.       return 0;
  236.     }
  237.     case WM_SIZE:
  238.         topx = SHORT1FROMMP(mp2);
  239.         topy = SHORT2FROMMP(mp2); 
  240.         return 0;
  241.  
  242.     case WM_ERASEBACKGROUND:
  243.       /*
  244.        * Return TRUE to request PM to paint the window background
  245.        * in SYSCLR_WINDOW.
  246.        */
  247.       return (MRESULT)( TRUE );
  248.  
  249.     case WM_CHAR:
  250.     {
  251.         CHAR keycode, skeycode[2];
  252.         INT i;
  253.  
  254.         if (!(CHARMSG(&msg)->fs & KC_CHAR)) return 0; /* we're not interested */
  255.         if (CHARMSG(&msg)->fs & KC_KEYUP) return 0;
  256.  
  257.         if (!anykeyhit) {
  258.            i = DosGetDateTime(&dt);
  259.            startsec = (float) (dt.hours*3600 + dt.minutes*60 + dt.seconds);
  260.            anykeyhit = 1;
  261.         } /* endif */
  262.  
  263.         keycode = CHARMSG(&msg)->chr;
  264.         if ((keycode == 13) || (keycode == ' ')) { /* end of word? */
  265.            for (i=0;i<30;i++) {
  266.                 if (!wordx[i]) continue;
  267.                 if (  !respectCase && !stricmp(kbbuf,words[i]) ||  /* hit! */
  268.                        respectCase && !strcmp (kbbuf,words[i])) {
  269.                    score++;
  270.                    activewords--;
  271.                    wordx[i] = 0;
  272.                    if (sound) DosBeep(2000,40);
  273.                    wordcountcorr++;
  274.                    if ( (score%20)==0) {
  275.                       if (maxactivewords<29)
  276.                          maxactivewords++;
  277.                       if (score%50==0) {
  278.                          timertime -= 20;
  279.                          maxactivewords /= 2;
  280.                          if (timertime < 50) timertime = 50;
  281.                          WinStartTimer(hab, hwnd, 1, timertime);
  282.                          if (sound) DosBeep(4000,40);
  283.                       }
  284.                    }
  285.                 break;
  286.                 }/* hit */
  287.            }
  288.            wordcount++;
  289.            kbbuf[0]=0;
  290.            return 0;
  291.         } /* user hit space or c/r */
  292.         skeycode[0] = keycode;
  293.         skeycode[1] = 0;
  294.         strcat(kbbuf,skeycode);
  295.         return 0;
  296.     }
  297.  
  298.     case WM_SETFOCUS:
  299.         if (SHORT1FROMMP(mp2)) /* if we got focus */
  300.                 pausemode = 0;
  301.         else
  302.                 pausemode = 1;
  303.         return 0;
  304.  
  305.     case WM_TIMER:
  306.     {
  307.         HPS hps;
  308.         RECTL  rc;   
  309.         INT i,wordsize;
  310.  
  311.         if (pausemode || gameover) break;
  312.         if (activewords < 4 && maxactivewords>5) {
  313.               timertime -= 50;
  314.               if (timertime<51) timertime=51;
  315.               WinStartTimer(hab, hwnd, 1, timertime);
  316.         }
  317.         if (activewords < maxactivewords) {
  318.            for (i=0;i<30;i++)
  319.                if (wordx[i] == 0) break;
  320.         /* Creating a new word.. */
  321.            if (i<30) {
  322.               activewords++;
  323.               wordx[i] = rand() % topx + 1;
  324.               strcpy(words[i],findword());
  325.               wordsize = CharWidth*(strlen(words[i])+1);
  326.               if (wordx[i]+wordsize > topx ) {
  327.                   wordx[i] -= wordsize;
  328.                   if (wordx[i]<1) wordx[i]=1;
  329.               }
  330.               wordy[i] = topy-1;
  331.            }
  332.         }
  333.         WinInvalidateRect(hwnd,NULL,FALSE);
  334.  
  335.         /* move down everyone by one */
  336.         for (i=0;i<30;i++) {
  337.             if (wordx[i] !=0) {
  338.                 pt.x = wordx[i];
  339.                 pt.y = wordy[i];
  340.                 /* move down */
  341.                 wordy[i] -= CharHeight+1;
  342.                 /* reach the bottom? */
  343.                 if (wordy[i] < CharHeight) {
  344.                    wordx[i] = 0;
  345.                    if (anykeyhit) {
  346.                         lost++;
  347.                         if (sound) DosBeep(400,10); }
  348.                    activewords--;
  349.                    if (lost>14) {
  350.                       gameover = 1;
  351.                       break;
  352.                    }
  353.                 }
  354.                 pt.y = wordy[i];
  355.             }
  356.         }
  357.         break;
  358.     }
  359.  
  360.     case WM_PAINT:
  361.       /*
  362.        * Window contents are drawn here in WM_PAINT processing.
  363.        */
  364.       {
  365.       HPS    hps;                       /* Presentation Space handle    */
  366.       RECTL  rc,rcl;
  367.       POINTL pt;                        /* String screen coordinates    */
  368.                                         /* Create a presentation space  */
  369.       CHAR dest;
  370.       INT i;
  371.       CHAR buffer[80];
  372.       DATETIME dt;
  373.       float elapsedsec;
  374.  
  375.       WinQueryWindowRect(hwnd, &rcl);
  376.       topx = rcl.xRight;
  377.       topy = rcl.yTop; 
  378.  
  379.  
  380.       hps = WinBeginPaint( hwnd, 0L, &rc );
  381.       GpiErase(hps);
  382.       GpiSetColor( hps, CLR_NEUTRAL );         /* colour of the text,   */
  383.       GpiSetBackColor( hps, CLR_BACKGROUND );  /* its background and    */
  384.       GpiSetBackMix( hps, BM_OVERPAINT );      /* how it mixes,         */
  385.                                                /* and draw the string...*/
  386.       if (gameover) {
  387.          pt.x = 10;
  388.          pt.y = topy - 60;
  389.          DosGetDateTime(&dt);
  390.          WinStopTimer(hab, hwnd, 1);
  391.          elapsedsec = (float) (dt.hours*3600+dt.minutes*60+dt.seconds) - startsec;
  392.          if (elapsedsec == 0L) elapsedsec = 1L;
  393.          sprintf(buffer,"That's %d words. You got %d words right, ",lost,score);
  394.          GpiCharStringAt(hps,&pt,(LONG)strlen(buffer),buffer);
  395.          pt.y -= CharHeight*2;
  396.          sprintf(buffer,"and your WPM=%3.1f, correct WPM=%3.1f",
  397.             (float) wordcount / elapsedsec * 60.0,
  398.             (float) wordcountcorr / elapsedsec * 60.0);
  399.          GpiCharStringAt(hps,&pt,(LONG)strlen(buffer),buffer);
  400.          pt.y -= CharHeight*2;
  401.          strcpy(buffer,"Select \"Restart\" for another game.");
  402.          GpiCharStringAt(hps,&pt,(LONG)strlen(buffer),buffer);
  403.       }
  404.       else
  405.         for (i=0;i<30;i++)
  406.           if (wordx[i] != 0) {
  407.                 pt.y = wordy[i];
  408.                 pt.x = wordx[i];
  409.                 GpiCharStringAt( hps, &pt, (LONG)strlen(words[i]), words[i]);
  410.           }
  411.  
  412.       WinEndPaint( hps );                      /* Drawing is complete   */
  413.       return 0;
  414.       }
  415.  
  416.     case WM_CLOSE:
  417.       /*
  418.        * This is the place to put your termination routines
  419.        */
  420.       fclose(wordfile);
  421.       WinPostMsg( hwnd, WM_QUIT, (MPARAM)0,(MPARAM)0 );/* Cause termination*/
  422.       break;
  423.  
  424.     default:
  425.       /*
  426.        * Everything else comes here.  This call MUST exist
  427.        * in your window procedure.
  428.        */
  429.  
  430.       return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  431.   }
  432.   return (MRESULT)FALSE;
  433. } /* End of MyWindowProc */
  434.  
  435. /**************************************************************************
  436.  *
  437.  *  Name       : AbortTypeFast
  438.  *
  439.  *  Description: Report an error returned from an API service
  440.  *
  441.  *  Concepts   :  use of message box to display information
  442.  *
  443.  *  API's      :  DosBeep
  444.  *                WinGetErrorInfo
  445.  *                WinMessageBox
  446.  *                WinFreeErrorInfo
  447.  *                WinPostMsg
  448.  *
  449.  *  Parameters :  hwndFrame = frame window handle
  450.  *                hwndClient = client window handle
  451.  *
  452.  *  Return     :  [none]
  453.  *
  454.  *************************************************************************/
  455. VOID AbortTypeFast(HWND hwndFrame, HWND hwndClient)
  456. {
  457.    PERRINFO  pErrInfoBlk;
  458.    PSZ       pszOffSet;
  459.    void      stdprint(void);
  460.  
  461.    if (sound) DosBeep(100,50);
  462.    if ((pErrInfoBlk = WinGetErrorInfo(hab)) != (PERRINFO)NULL)
  463.    {
  464.       pszOffSet = ((PSZ)pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
  465.       pszErrMsg = ((PSZ)pErrInfoBlk) + *((PSHORT)pszOffSet);
  466.       if((INT)hwndFrame && (INT)hwndClient)
  467.          WinMessageBox(HWND_DESKTOP,         /* Parent window is desk top */
  468.                        hwndFrame,            /* Owner window is our frame */
  469.                        (PSZ)pszErrMsg,       /* PMWIN Error message       */
  470.                        "Error Msg",          /* Title bar message         */
  471.                        MSGBOXID,             /* Message identifier        */
  472.                        MB_MOVEABLE | MB_CUACRITICAL | MB_CANCEL ); /* Flags */
  473.       WinFreeErrorInfo(pErrInfoBlk);
  474.    }
  475.    WinPostMsg(hwndClient, WM_QUIT, (MPARAM)NULL, (MPARAM)NULL);
  476. } /* End of AbortTypeFast */
  477.  
  478.  
  479. INT notify(HWND hwndFrame,char *blurb, INT code)
  480. {
  481.    CHAR out[80];
  482.  
  483.    sprintf(out,blurb,code);
  484.    if (sound) DosBeep(1000,100);
  485.    if (sound) DosBeep(2000,100);
  486.    if (sound) DosBeep(3000,100);
  487.    DosSleep(2000);
  488.    WinMessageBox(HWND_DESKTOP,
  489.                  hwndFrame,
  490.                 (PSZ) out,
  491.                  "Oops!",
  492.                  MSGBOXID,
  493.                  MB_MOVEABLE | MB_INFORMATION | MB_OK ); /* Flags */
  494. }
  495.  
  496. BOOL goodword(char *p)
  497. {
  498.    INT i;
  499.         /* we admit short words, but not too often */
  500.         if (strlen(p)<3) return 0; /* not too short */
  501.         if (strlen(p)<5 && rand()<20000) return 0;
  502.         for (i=0;i<30;i++)
  503.            if (wordx[i] && stricmp(p,words[i])==0) return 0;
  504.  
  505.         while (*p) {
  506.                 if (ispunct(*p)) return 0;
  507.                 p++; 
  508.         }
  509.         return 1;
  510. }
  511.  
  512. CHAR *findword() {
  513.    static CHAR wordfound[40];
  514.    CHAR buffer[255];
  515.    INT i=0;
  516.  
  517.    wordfound[0]=0;
  518.    while (!goodword(wordfound)) {
  519.       readline(buffer);
  520.       if (buffer[0] == 0) return NULL; /* error reading  */
  521.       while (!isspace(*(buffer+i))) {  /* find a space.. */
  522.         i++;
  523.         if (*(buffer+i) == '\0') {
  524.            i=0;
  525.            readline(buffer);
  526.         }
  527.       }
  528.       while (isspace(*(buffer+i))) { /* find a non-space */
  529.         i++;
  530.         if (*(buffer+i) == '\0') {
  531.                 i=0;
  532.                 readline(buffer); 
  533.         }
  534.       }
  535.       sscanf(buffer+i,"%s",wordfound);
  536.    }
  537.    return wordfound;
  538. }
  539. INT readline(char *p)
  540. {
  541.       *p = 0;
  542.       while (1) {
  543.               fseek (wordfile,(LONG) rand()%80L, SEEK_CUR);
  544.               if (fgets(p,250,wordfile) == NULL) {
  545.                 fclose(wordfile);
  546.                 wordfile = fopen("TYPEFAST.DAT","rb");
  547.                 if (wordfile == NULL) return 1;
  548.                 fseek(wordfile,1L,SEEK_SET);
  549.                 continue; }
  550.               break;
  551.       }
  552. }
  553.  
  554. INT init() {
  555.    INT i;
  556.  
  557.    activewords = 0;
  558.    lost = 0;   score = 0;  maxactivewords=4; timertime=ID_EASY;
  559.    topx = 400L; topy = 400L; anykeyhit=0; pausemode=0; gameover=0;
  560.    wordcount=0L; wordcountcorr=0L; lastwordheight=0;
  561.    kbbuf[0]=0; sound=1;
  562.    for(i=0;i<30;i++)
  563.       wordx[i]=0;
  564. }
  565.  
  566.